home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Developer Essentials / DTS Sample Code / Macintosh Sample Code / SC.023.FracApp 2.0 / GoFigger.a < prev    next >
Encoding:
Text File  |  1990-04-30  |  14.2 KB  |  375 lines  |  [TEXT/MPS ]

  1. ; ====================================================================================
  2. ;
  3. ;    Program:    FracApp 2.0
  4. ;    File:        GoFigger.a
  5. ;
  6. ;    by Keith Rollin & Bo3b Johnson
  7. ;    of Apple Macintosh Developer Technical Support
  8. ;
  9. ;    Copyright © 1988-1990 Apple Computer, Inc.
  10. ;    All rights reserved.
  11. ;
  12. ; ====================================================================================
  13. ;
  14. ;    Assembly support routines for FracApp 2.0
  15. ;
  16. ;    InsTimeNoDrift - Installs a Time Manager Task, using Extended Time Manager if
  17. ;            present
  18. ;    TimeCounterThatFetchesItsOwnTaskPtr - Task that gets called on Systems earlier
  19. ;            than 6.0.2
  20. ;    TimeCounter - Task that gets called on System 6.0.2 or later
  21. ;    InitCounter - Called to initialize the TimeCounterThatFetchesItsOwnTaskPtr with
  22. ;            a reference to our global variables.
  23. ;    GoFigger - Given a point, a range, and a dwell threshhold, returns the number of
  24. ;            iterations to go beyond the range.
  25. ;
  26. ; ====================================================================================
  27.  
  28.                 MC68881
  29.             if qNeedsMC68020 then
  30.                 MACHINE MC68020
  31.             elseif qNeedsMC68030 then
  32.                 MACHINE MC68030
  33.             endif
  34.  
  35.                 INCLUDE    'Traps.a'
  36.  
  37.  
  38. ; ====================================================================================
  39. ;
  40. ; PROCEDURE InsTimeNoDrift(taskRecPtr:TMTaskPtr);
  41. ;
  42. ;    Install a Time Manager task. This is a copy of the glue that comes with MPW for
  43. ;    performing such a task, except that we use Trap $A458 instead of $A058. This gets
  44. ;    us to the same place in ROM, but the fact that bit 9 is set means something to
  45. ;    the extended Time Manager in System 7.0; it is harmless for earlier systems. See
  46. ;    Inside mac, page I-89 to see the format of the trap word and what bit 9 means for
  47. ;    Operating System Traps.
  48. ;
  49. ;    So what does setting bit 9 mean? On systems that support it, it means "no-drift"
  50. ;    mode. This means that the Time Manager accounts for the overhead involved with
  51. ;    managing tasks, and the time it takes for your task procedure to execute. Your
  52. ;    task will be called with the frequency that you specified, rather than with an
  53. ;    interval of <specified period> + <Time Manager Overhead> + <Task execution time>.
  54. ;    Basically, what I mean is that it's more accurate.
  55. ;
  56. ; ====================================================================================
  57.  
  58. _InsXTimeTrap    OPWORD        $A458
  59.  
  60.                 SEG        'AInit'
  61. INSTIMENODRIFT    PROC     EXPORT
  62.  
  63. StackFrame        RECORD    {RetAddr},DECR        ; build a stack frame record
  64. taskRecPtr        DS.L    1                    ; pointer task record we are using
  65. ParamSize        EQU        StackFrame-*        ; size of all the passed parameters
  66. RetAddr         DS.L    1                    ; place holder for return address
  67.                 ENDR
  68.  
  69.                 WITH    StackFrame
  70.  
  71.                 MOVEA.L    taskRecPtr(A7),A0    ; get the record pointer
  72.                 _InsXTimeTrap                ; Install the task
  73.  
  74.             if qNeedsMC68020 | qNeedsMC68030 then
  75.  
  76.                 RTD        #ParamSize
  77.  
  78.             else
  79.  
  80.                 MOVEA.L    (A7)+,A0            ; pop the return address
  81.                 ADD        #ParamSize,A7        ; trash the parameter
  82.                 JMP        (A0)                ; return
  83.  
  84.             endif
  85.  
  86.                 ENDP
  87.  
  88. ; ====================================================================================
  89. ;
  90. ; InitCounter
  91. ;    Called when we aren't running under System 6.0.2 or later. Under those newer
  92. ;    systems, the Time Manager calls our task procedure with A1 holding a pointer to
  93. ;    our task record. This gives us the foothold we need to get at our global
  94. ;    variables. For instance, just preceeding my task record, I have a variable that
  95. ;    holds my A5 value. Once I have this, I can access any of my global variables.
  96. ;    The problem is that we don't get this pointer in A1 on older systems. Therefore,
  97. ;    I call InitCounter with with that pointer, and save it locally.
  98. ;
  99. ; TimeCounterThatFetchesItsOwnTaskPtr
  100. ;    Gets the pointer to my time manager task record, and falls to TimeCounter. This
  101. ;    routine gets installed on older systems that don't have a Time Manager that
  102. ;    passes to us a pointer to our task record in A1. In that case, we have to
  103. ;    remember the pointer ourselves. We can't save it in a global, as our time
  104. ;    counter gets called at interrupt time, and there is no guarantee that A5 points
  105. ;    to our globals. Neither is there a way to find out what A5 should be set to,
  106. ;    so we can't just save A5, set it to the right value, do our thing, and then
  107. ;    restore A5. The only way to remember our task record pointer is to save it
  108. ;    locally, and retrieve it with PC relative addressing.
  109. ;
  110. ; TimeCounter
  111. ;    Retrieves my saved A5 value, gets a reference to gCounter, and increments it.
  112. ;    This way, gCounter is like a running stopwatch with millisecond resolution.
  113. ;    Whenever I need to timestamp something, I just look at gCounter. It's kind of
  114. ;    like calling the Ticks system routine, but better. Ticks aren't good enough
  115. ;    because we would like to be able to chunk up our operations into units small
  116. ;    enough that we don't upset the user. In other words, we want responsiveness
  117. ;    to be very high. With this goal, we wouldn't be able to do timing with Ticks
  118. ;    as we would like to be in and out of our calculation routines in less than
  119. ;    1/60 of a second. So we use a timer with a higher resolution, i.e., the
  120. ;    Time Manager.
  121. ;
  122. ; ====================================================================================
  123.                 SEG        'ARes'
  124. INITCOUNTER        PROC     EXPORT
  125.                 IMPORT    GCOUNTER:Data
  126.                 EXPORT    TIMECOUNTERTHATFETCHESITSOWNTASKPTR
  127.                 EXPORT    TIMECOUNTER
  128.  
  129. TimeRecord        RECORD    {qHeader}
  130. myA5            DS.L    1                    ; holds our A5 for our globals
  131. qHeader            DS.B    6                    ; standard OS queue header
  132. tmAddr            DS.L    1                    ; service routine [pointer]
  133. tmCount         DS.L    1                    ; timeout count [long]
  134. tmQSize         EQU        *
  135.                 ENDR
  136.  
  137.                 WITH TimeRecord
  138.  
  139.                 MOVE.L    (SP)+,A0            ; get return address, save in register A0
  140.                 LEA        tmTaskPtr,A1        ; get a pointer to local storage
  141.                 MOVE.L    (SP)+,(A1)            ; put pointer to task record into local storage
  142.                 JMP        (A0)                ; return to caller
  143.  
  144. TIMECOUNTERTHATFETCHESITSOWNTASKPTR
  145.                 MOVE.L    tmTaskPtr(PC),A1    ; retrieve the pointer to task record
  146. TIMECOUNTER
  147.                 MOVE.L    myA5(A1),A0            ; get our A5 value
  148.                 ADDQ.L    #1,GCOUNTER(A0)        ; increment our global gCounter
  149.                 MOVE.L    A1,A0                ; put task pointer in A0 for PrimeTime
  150.                 MOVEQ.L    #1,D0                ; wake up time or 1 millisecond
  151.                 _PrimeTime                    ; re-install ourselves
  152.                 RTS
  153.  
  154. tmTaskPtr        DC.L    0                    ; holds pointer to time task record on
  155.                                             ; old systems that won't pass it to us
  156.                                             ; when they call us.
  157.  
  158.                 ENDP
  159.  
  160.  
  161. ; ====================================================================================
  162. ;
  163. ; PROCEDURE GoFigger(x, y, Po, Qo: Extended; M, K: Integer; VAR kol: Integer);
  164. ;
  165. ;    This is the heart and soul of this program. Given a point and some other
  166. ;    defining constants, this routine figures out what color the point should be.
  167. ;    It works like this:
  168. ;
  169. ;    Mandelbrot fractals are calculated on the complex coordinate plane. This means
  170. ;    that complex numbers of the form a + ib are plotted in x,y fashion on a two
  171. ;    dimensional grid. The value 'a' is plotted in the x, or real, direction, and
  172. ;    the value 'b' is plotted in the y, or imaginary, direction.
  173. ;
  174. ;    Given a point a + ib, we square it and add a complex constant C = Po + iQo. We
  175. ;    then check to see how far the result is away from the first point. If it is
  176. ;    farther than some limit (called M here), we are done. If the result is within
  177. ;    that limit, we apply the formula again to that result. We keep this process up
  178. ;    until we either go outside the limit "M", or we have performed this process a
  179. ;    certain number of times (called the dwell limit). It is this number of
  180. ;    iterations that determines the color of the pixel. If we exceed our maximum
  181. ;    number of iterations, we map the color to black.
  182. ;
  183. ; ====================================================================================
  184.  
  185.                 SEG        'ARes'
  186. TFRACAPPENGINE_GOFIGGER    PROC    EXPORT
  187.  
  188. StackFrame        RECORD    {A6Link},DECR
  189. xPtr            DS.L    1                        ; ptr to initial 'a'
  190. yPtr            DS.L    1                        ; ptr to initial 'b'
  191. PoPtr            DS.L    1                        ; ptr to real part of constant
  192. QoPtr            DS.L    1                        ; ptr to imag part of constant
  193. M                DS.W    1                        ; maximum distance to roam
  194. K                DS.W    1                        ; dwell limit
  195. kolPtr            DS.L    1                        ; location to return iteration count
  196. SELF            DS.L    1                        ; reference to myself (my object)
  197. ParamSize        EQU        StackFrame-*            ; size of all the passed parameters
  198. RetAddr            DS.L    1                        ; place holder for return address
  199. A6Link            DS.L    1
  200.                 ENDR
  201.  
  202. x                EQU        FP7                        ; hold in register for speed
  203. y                EQU        FP6                        ; hold in register for speed
  204. Po                EQU        FP5                        ; hold in register for speed
  205. Qo                EQU        FP4                        ; hold in register for speed
  206. xSquared        EQU        FP3                        ;
  207. ySquared        EQU        FP2
  208. radius            EQU        FP1                        ; holds 'M' for speed
  209. scratch            EQU        FP0
  210.  
  211. dwellMax        EQU        D1                        ; holds 'K' for speed
  212. countDown        EQU        D2                        ; holds number of iterations
  213.  
  214. savedRegs        REG        D1-D2
  215. savedFPRegs        FREG    FP4-FP7
  216.  
  217.                 WITH     StackFrame
  218.  
  219.                 LINK    A6,#A6Link            ; Link so that I can get to my VARs
  220.                 MOVEM.L    savedRegs,-(A7)        ; Save the registers I'll trash that...
  221.                 FMOVEM    savedFPRegs,-(A7)    ; ...aren't defined as scratch registers
  222.  
  223.                 MOVEA.L    QoPtr(A6),A0        ; Get my initial point
  224.                 FMOVE.X    (A0),Qo
  225.                 MOVEA.L    PoPtr(A6),A0
  226.                 FMOVE.X    (A0),Po
  227.  
  228.                 MOVEA.L    yPtr(A6),A0            ; Get the origin
  229.                 FMOVE.X    (A0),y
  230.                 MOVEA.L    xPtr(A6),A0
  231.                 FMOVE.X    (A0),x
  232.  
  233.                 MOVE    K(A6),dwellMax        ; Get my dwell time
  234.                 FMOVE.W    M(A6),radius        ; Get the distance limit
  235.  
  236.                 MOVE    dwellMax,countDown    ; set counter to maximum (we'll count down)
  237.  
  238.                 BRA.S    TestEnd
  239.  
  240. ;            Given a point: pt = x + iy,
  241. ;            and a constant: C = Po + iQo,
  242. ;            iteratively calculate pt2 = pt^2 + C
  243. ;                                      = (x + iy)^2 + (Po + iQo)
  244. ;                                      = (x^2 + 2ixy - y^2) + (Po + iQo)
  245. ;                                      = (x^2  - y^2 + Po) + i(2xy + Qo)
  246. ;            until pt2 is at least "M" units from the original point.
  247. ;            The number of times that it took us to get to this state gets
  248. ;            mapped into the color that we use for that point. If we iterated more
  249. ;            than a certain maximum, then we cap the color to that maximum.
  250.  
  251. loop
  252.                                         ; Make y := 2*x*y + Qo
  253.                 FADD    y,y                    ; y := y+y := 2*y
  254.                 FMUL    x,y                    ; y := x*y := x*(2*y) := 2*x*y
  255.                 FADD    Qo,y                ; y := 2*x*y + Qo
  256.  
  257.                 FMOVE.X    xSquared,x            ; x := x^2 - y^2 + Po
  258.                 FSUB    ySquared,x
  259.                 FADD    Po,x
  260.  
  261.  
  262. TestEnd
  263.                 FMOVE.X    y,ySquared            ; ySquared := y*y
  264.                 FMUL    y,ySquared
  265.                 FMOVE.X    x,xSquared            ; xSquared := x*x
  266.                 FMUL    x,xSquared
  267.  
  268.                 FMOVE.X    ySquared,scratch    ; is xSquared + ySquared > radius?
  269.                 FADD    xSquared,scratch
  270.                 FCMP    radius,scratch
  271.                 FDBGE    countDown,loop        ; no (also, test the threshold counter)
  272.  
  273. OutaHere
  274.                 MOVEA.L    kolPtr(A6),A0        ; get a pointer to our return variable
  275.                 SUB        countDown,dwellMax    ; get number of iterations
  276.                 MOVE    dwellMax,(A0)        ; store number iterations into kol
  277.                 FMOVEM    (A7)+,savedFPRegs    ; restore the registers we nuked
  278.                 MOVEM.L    (A7)+,savedRegs
  279.                 UNLK    A6
  280.  
  281.             if qNeedsMC68020 | qNeedsMC68030 then
  282.  
  283.                 RTD        #ParamSize            ; Nice, fast 68020 return
  284.  
  285.             else
  286.  
  287.                 MOVEA.L    (A7)+,A0            ; pop the return address
  288.                 ADD        #ParamSize,A7        ; trash the parameter
  289.                 JMP        (A0)                ; return
  290.  
  291.             endif
  292.  
  293.                 ENDP
  294.                 END
  295.  
  296.  
  297.  
  298.                         == ==== ======== == ==== ==== ==
  299.                         =  TIME ANALYSIS OF CORE LOOP  =
  300.                         == ==== ======== == ==== ==== ==
  301.  
  302. ;
  303. ; This is an analysis of the loop of GoFigger that extends from the "loop" label
  304. ; all the way down to the FDGBE instruction (just before the "OoutaHere" label).
  305. ; Using the performance tools, I've noticed that FracApp spends most of its time
  306. ; in this loop (as much as 80-90%). Therefore, it's very critical that this loop
  307. ; run as fast as possible, so that we can see our pictures as fast as possible.
  308. ;
  309. ; This routine was originally written in Pascal, and compiled with FPU code
  310. ; generation turned on. The first thing we did to make this faster was to recode
  311. ; it into Assembly. After that we did an analysis to make sure that this code was
  312. ; as fast as possible, taking into account the caching capabilities of the 68882.
  313. ; following is results of that analysis.
  314. ;
  315. ; This analysis follows the procedure outlined in section 8.5.1.3 of the Motorola
  316. ; MC68881/MC68882 Floating Point Coprocessor User's Manual
  317. ;
  318.  
  319.                           68881          68882        Tail    Next Head    Overlap := Min(Tail, NextHead)
  320.                           -----          -----        ----    ---------    -------
  321. FADD    y,y                    51        56/17/35     35            17          17
  322. FMUL    x,y                    71        76/17/55     55            17          17
  323. FADD    Qo,y                51        56/17/35     35          21+17          35
  324.  
  325. FMOVE.X    xSquared,x            33        21/21/00     -            -          -
  326. FSUB    ySquared,x            51        56/17/35     35            17          17
  327. FADD    Po,x                51        56/17/35     35          21+17          35
  328.  
  329. FMOVE.X    y,ySquared            33        21/21/00     -            -          -
  330. FMUL    y,ySquared            71        76/17/55     55          21+17          38
  331. FMOVE.X    x,xSquared            33        21/21/00     -            -          -
  332. FMUL    x,xSquared            71        76/17/55     55          21+17          38
  333.  
  334. FMOVE.X    ySquared,scratch    33        21/21/00     -            -          -
  335. FADD    xSquared,scratch    51        56/17/35     35            17          17
  336. FCMP    radius,scratch        33        38/17/17     -            -          -
  337.                           ----        --------    ---------------------------
  338.                            633        630                        Overlap = 214
  339.  
  340. Net results:
  341. 68881            = 633
  342. 68882 = 630-214    = 416
  343. ratio = 633/416 = 1.52
  344.  
  345. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  346. ;
  347. ; The following is a little chart that should give you an idea what happens with
  348. ; the concurrency feature of the MC68882. The head of the first instruction is
  349. ; executed. When that is done, it proceeds to the tail of the first instruction,
  350. ; and the head of the second instruction is entered. When both the tail of the
  351. ; first instruction and the head of the second instruction are done, we move into
  352. ; the tail of the second instruction, and proceed to the head of the third
  353. ; instruction. Some instructions, like FMOVE, have no tails, and can execute
  354. ; completely before the tail of the previous instruction is done, and can proceed
  355. ; to the head of the instruction that comes after it. Note that all of this
  356. ; occurs only if there is no register conflict. See the “Motorola MC68881/MC68882
  357. ; Floating Point Coprocessor User's Manual” and “Macintosh Technote #236: Speedy
  358. ; the Math Coprocessor” for more information.
  359. ;
  360. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  361.  
  362. FADD    + 17 -+---- 35 ----+
  363. FMUL          + 17 -+       +------- 55 -------+
  364. FADD                       + 17 -+              +---- 35 ----+
  365. FMOVE                                          +- 21 --+
  366. FSUB                                                  + 17 -+---- 35 ----+
  367. FADD                                                        + 17 -+         +---- 35 ----+
  368. FMOVE                                                                     +- 21 --+
  369. FMUL                                                                             + 17 -+------- 55 -------+
  370. FMOVE                                                                                   +- 21 --+
  371. FMUL                                                                                           + 17 -+      +------- 55 -------+
  372. FMOVE                                                                                                      +- 21 --+
  373. FADD                                                                                                              + 17 -+     +---- 35 ----+
  374. FCMP                                                                                                                         + 17 -+      + 17 -+
  375.